/*
Copyright © 2023 NAME HERE <EMAIL ADDRESS>

*/
package cmd

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"

	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

// pemCmd represents the pem command
var pemCmd = &cobra.Command{
	Use:   "pem",
	Short: "查看证书的相关信息",
	Long:  ``,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("read file", args[0])
		LoadCertficateAndKeyFromFile(args[0])
	},
}

func init() {
	rootCmd.AddCommand(pemCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// pemCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// pemCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// LoadCertficateAndKeyFromFile reads file, divides into key and certificates
func LoadCertficateAndKeyFromFile(path string) (*tls.Certificate, error) {
	raw, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	var cert tls.Certificate
	for {
		block, rest := pem.Decode(raw)
		if block == nil {
			break
		}
		if block.Type == "CERTIFICATE" {
			cert.Certificate = append(cert.Certificate, block.Bytes)
			parsed, err := x509.ParseCertificate(block.Bytes)
			if err == nil {
				fmt.Println("Subject to", parsed.Subject)
				fmt.Println("Valid from", parsed.NotBefore)
				fmt.Println("Valid until", parsed.NotAfter)
			}
		} else {
			var _err error
			cert.PrivateKey, _err = parsePrivateKey(block.Bytes)
			if _err != nil {
				logrus.Errorf("Failure reading private key from \"%s\": %s", path, _err)
			}
		}
		raw = rest
	}

	// if len(cert.Certificate) == 0 {
	// 	return nil, fmt.Errorf("No certificate found in \"%s\"", path)
	// } else if cert.PrivateKey == nil {
	// 	return nil, fmt.Errorf("No private key found in \"%s\"", path)
	// }

	return &cert, nil
}

func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
		return key, nil
	}
	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
		switch key := key.(type) {
		case *rsa.PrivateKey, *ecdsa.PrivateKey:
			return key, nil
		default:
			return nil, fmt.Errorf("Found unknown private key type in PKCS#8 wrapping")
		}
	}
	if key, err := x509.ParseECPrivateKey(der); err == nil {
		return key, nil
	}
	return nil, fmt.Errorf("Failed to parse private key")
}
